package cn.openea.perpartner.meily.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.openea.perpartner.common.core.utils.StringUtils;
import cn.openea.perpartner.common.core.web.domain.Ztree;
import cn.openea.perpartner.meily.util.UserContext;
import cn.openea.perpartner.meily.web.convert.MenuTreeConvert;
import cn.openea.perpartner.meily.web.entity.*;
import cn.openea.perpartner.meily.web.entity.dto.MenuTreeDto;
import cn.openea.perpartner.meily.web.entity.vo.MenuTree;
import cn.openea.perpartner.meily.web.mapper.MenuMapper;
import cn.openea.perpartner.meily.web.service.IMenuService;
import cn.openea.perpartner.meily.web.service.IRoleMenuService;
import cn.openea.perpartner.meily.web.service.IRoleService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 菜单权限表(Menu)表服务实现类
 *
 * @author Weird077
 * @since 2023-03-15 16:17:56
 */
@Slf4j
@Service
public class MenuServiceImpl extends MPJBaseServiceImpl<MenuMapper, Menu> implements IMenuService {

    @Autowired
    private IRoleService roleService;
    @Autowired
    private IRoleMenuService roleMenuService;
    @Override
    public List<Menu> selectMenuList(Menu menu) {
        List<Menu> menuList = null;
        if (UserContext.isAdmin()) {
            menuList = selectMenuNormalAll(menu);
        } else {
            menuList = selectMenuListByUserId(menu);
        }
        return menuList;
    }


    @Override
    public List<Menu> selectMenuAll(String userId) {
        List<Menu> menuList;
        if (UserContext.isAdmin()) {
            LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
            wrapper.orderByAsc(Menu::getParentId);
            wrapper.orderByAsc(Menu::getOrderNum);
            menuList = list(wrapper);
        } else {
            menuList = baseMapper.selectMenuAllByUserId(userId);
        }
        return menuList;
    }

    @Override
    public int selectCountMenuByParentId(Long menuId) {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getParentId, menuId);
        return (int) count(wrapper);
    }

    @Override
    public int selectCountRoleMenuByMenuId(Long menuId) {
        LambdaQueryWrapper<RoleMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RoleMenu::getMenuId, menuId);
        return (int) roleMenuService.count(wrapper);
    }

    @Override
    public boolean checkMenuNameUnique(Menu menu) {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getMenuName, menu.getMenuName());
        wrapper.eq(Menu::getParentId, menu.getParentId());
        wrapper.last("limit 1");
        Menu info = getOne(wrapper);
        return BeanUtil.isNotEmpty(info);
    }

    @Override
    public List<MenuTree> selectMenusByUser(String userid) {
        MPJLambdaWrapper<Menu> wrapper = new MPJLambdaWrapper<>();
        wrapper.selectAll(Menu.class);
        wrapper.distinct();
        if (!UserContext.isAdmin()) {
            wrapper.leftJoin(RoleMenu.class, RoleMenu::getMenuId, Menu::getMenuId);
            wrapper.leftJoin(UserRole.class, UserRole::getRoleId, RoleMenu::getRoleId);
            wrapper.leftJoin(Role.class, Role::getRoleId, UserRole::getRoleId);
            wrapper.leftJoin(User.class, User::getUserId, UserRole::getUserId);
            wrapper.eq(UserRole::getUserId, userid);
            wrapper.eq(Role::getStatus, "0");
            wrapper.eq(User::getStatus, "0");
        }
        wrapper.eq(Menu::getVisible, 0);
        wrapper.orderByAsc(Menu::getParentId);
        wrapper.orderByAsc(Menu::getOrderNum);
        List<Menu> menus = list(wrapper);
        List<MenuTree> menuTrees = new ArrayList<>();
        menus.forEach(menu -> {
            MenuTree menuTree = new MenuTree();
            menuTree.setTitle(menu.getMenuName());
            menuTree.setHref(menu.getUrl());
            menuTree.setIcon(menu.getIcon());
            menuTree.setMenuId(menu.getMenuId());
            menuTree.setParentId(menu.getParentId());
            menuTrees.add(menuTree);
        });
        return getChildPerms(menuTrees, 0);
    }

    @Override
    public List<MenuTreeDto> roleMenuTreeData(Role role, String userId) {
        Long roleId = role.getRoleId();
        List<MenuTree> menuTrees;
        List<Menu> menuList = selectMenuAll(userId);
        if (StringUtils.isNotNull(roleId)) {
            List<String> roleMenuList = baseMapper.selectMenuTree(roleId);
            menuTrees = initZtree(menuList, roleMenuList);
        } else {
            menuTrees = initZtree(menuList, null);
        }
        menuTrees = getChildPerms(menuTrees,0);
        return menuTrees.stream().map(MenuTreeConvert.INSTANCE::toDto).collect(Collectors.toList());
    }

    @Override
    public List<Ztree> menuTreeData(String userId) {
        List<Menu> menuList = selectMenuAll(userId);

        return initZtree(menuList);
    }

    @Override
    public Menu selectMenuById(Long menuId) {
        return baseMapper.selectMenuById(menuId);
    }

    @Override
    public List<MenuTreeDto> menuTreeDtoData() {
        List<MenuTree> menuTrees = selectMenusByUser(UserContext.getUserId());
        MenuTreeConvert menuTreeConvert = MenuTreeConvert.INSTANCE;
        return menuTrees.stream().map(menuTreeConvert::toDto).collect(Collectors.toList());
    }

    //    ================================================ start 2022-04-23 add by lys ==============================================================
    /**
     *
     * 根据用户获取角色菜单列表
     * @param userId
     * @return
     */
    @Override
    public List<MenuTreeDto> roleMenuTreeData_staaff(String userId) {
        List<Menu> menuList = selectMenuAll_staff(userId);
        List<MenuTree> menuTrees = initZtree_staff(menuList);
        menuTrees = getChildPerms(menuTrees,0);
        return menuTrees.stream().map(MenuTreeConvert.INSTANCE::toDto).collect(Collectors.toList());
    }

    public List<Menu> selectMenuAll_staff(String userId) {
        List<Menu> menuList;
        if (roleService.checkAdmin(userId)) {
            LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
            wrapper.orderByAsc(Menu::getParentId);
            wrapper.orderByAsc(Menu::getOrderNum);
            menuList = list(wrapper);
        } else {
            menuList = baseMapper.selectMenuAllByUserId(userId);
        }
        return menuList;
    }

    /**
     * 对象转菜单树
     * @param menuList     菜单列表
     * @return 树结构列表
     */
    public List<MenuTree> initZtree_staff(List<Menu> menuList) {
        List<MenuTree> trees = new ArrayList<>();
        for (Menu menu : menuList) {
            MenuTree menuTree = new MenuTree();
            menuTree.setMenuId(menu.getMenuId());
            menuTree.setParentId(menu.getParentId());
            menuTree.setTitle(menu.getMenuName());
            menuTree.setIcon(menu.getIcon());
            menuTree.setHref(menu.getUrl());
            menuTree.setChecked(true);
            trees.add(menuTree);
        }
        return trees;
    }
// =================================================== end 2022-04-23 add by lys  ============================================================


    /**
     * 查询系统菜单列表
     *
     * @param menu 菜单信息
     * @return 菜单列表
     */
    private List<Menu> selectMenuListByUserId(Menu menu) {
        MPJLambdaWrapper<Menu> wrapper = new MPJLambdaWrapper<Menu>()
                .selectAll(Menu.class)
                .leftJoin(RoleMenu.class, RoleMenu::getMenuId, Menu::getMenuId)
                .leftJoin(UserRole.class, UserRole::getRoleId, RoleMenu::getRoleId)
                .leftJoin(Role.class, Role::getRoleId, UserRole::getRoleId)
                .eq(UserRole::getUserId, UserContext.getUserId());
        if (StrUtil.isNotBlank(menu.getMenuName())) {
            wrapper.like(Menu::getMenuName, menu.getMenuName());
        }
        if (StrUtil.isNotBlank(menu.getVisible())) {
            wrapper.eq(Menu::getVisible, menu.getVisible());
        }
        wrapper.orderByAsc(Menu::getParentId);
        wrapper.orderByAsc(Menu::getOrderNum);
        return list(wrapper);
    }

    /**
     * trees
     *
     * @param menu 菜单信息
     * @return 菜单列表
     */
    private List<Menu> selectMenuNormalAll(Menu menu) {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(menu.getMenuName())) {
            wrapper.like(Menu::getMenuName, menu.getMenuName());
        }
        if (StrUtil.isNotBlank(menu.getVisible())) {
            wrapper.eq(Menu::getVisible, menu.getVisible());
        }
        wrapper.orderBy(true, true, Menu::getParentId, Menu::getOrderNum);
        return list(wrapper);
    }

    /**
     * 对象转菜单树
     *
     * @param menuList 菜单列表
     * @return 树结构列表
     */
    public List<Ztree> initZtree(List<Menu> menuList) {
        List<Ztree> trees = new ArrayList<>();
        for (Menu menu : menuList) {
            Ztree ztree = new Ztree();
            ztree.setId(menu.getMenuId());
            ztree.setPId(menu.getParentId());
            ztree.setName(menu.getMenuName());
            ztree.setTitle(menu.getMenuName());
            ztree.setIcon(menu.getIcon());
            ztree.setUrl(menu.getUrl());
            ztree.setOrderNum(menu.getOrderNum());
            ztree.setVisible(menu.getVisible());
            trees.add(ztree);
        }
        return trees;
    }

    /**
     * 对象转菜单树
     *
     * @param menuList     菜单列表
     * @param roleMenuList 角色已存在菜单列表
     * @return 树结构列表
     */
    public List<MenuTree> initZtree(List<Menu> menuList, List<String> roleMenuList) {
        List<MenuTree> trees = new ArrayList<>();
        boolean isCheck = StringUtils.isNotNull(roleMenuList);
        for (Menu menu : menuList) {
            MenuTree menuTree = new MenuTree();
            menuTree.setMenuId(menu.getMenuId());
            menuTree.setParentId(menu.getParentId());
            menuTree.setTitle(menu.getMenuName());
            menuTree.setIcon(menu.getIcon());
            menuTree.setHref(menu.getUrl());
            if (isCheck) {
                menuTree.setChecked(roleMenuList.contains(Convert.toStr(menu.getMenuId())));
            }
            trees.add(menuTree);
        }
        return trees;
    }

    /**
     * 根据父节点的ID获取所有子节点
     *
     * @param list     分类表
     * @param parentId 传入的父节点ID
     * @return String
     */
    public List<MenuTree> getChildPerms(List<MenuTree> list, int parentId) {
        List<MenuTree> returnList = new ArrayList<>();
        for (MenuTree t : list) {
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (t.getParentId() == parentId) {
                recursionFn(list, t);
                returnList.add(t);
            }
        }
        return returnList;
    }

    /**
     * 递归列表
     *
     */
    private void recursionFn(List<MenuTree> list, MenuTree t) {
        // 得到子节点列表
        List<MenuTree> childList = getChildList(list, t);
        t.setChild(childList);
        for (MenuTree tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<MenuTree> getChildList(List<MenuTree> list, MenuTree t) {
        List<MenuTree> tlist = new ArrayList<>();
        for (MenuTree n : list) {
            if (n.getParentId().longValue() == t.getMenuId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<MenuTree> list, MenuTree t) {
        return !getChildList(list, t).isEmpty();
    }
}

